Compare commits

..

No commits in common. "acd456c22a0e710c195a06e3eda486de0bff0c4b" and "36ab1b1769403c3b5f8f91047d391dcd186af98d" have entirely different histories.

5 changed files with 17 additions and 32813 deletions

View File

@ -1,84 +0,0 @@
use std::path::PathBuf;
use super::{CommandResponse, EditorBuffer};
use crate::{Point, TextBuffer, TextBufferWriter};
impl EditorBuffer {
pub fn open_file(&mut self, filepath: PathBuf) -> CommandResponse {
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()
);
self.filepath = Some(filepath);
self.cursor = Point::default();
self.buffer = buffer;
CommandResponse::Success(msg)
}
Err(err) => CommandResponse::Failure(format!("{}", err)),
}
}
Err(err) => {
if err.kind() == std::io::ErrorKind::NotFound {
CommandResponse::Failure(format!(
"File not found: \"{}\"",
filepath.to_string_lossy()
))
} else {
CommandResponse::Failure(format!("{}", err))
}
}
}
}
pub fn save_file(&mut self, _filepath: Option<PathBuf>) -> CommandResponse {
todo!()
}
}
#[cfg(test)]
mod tests {
use crate::{Command, CommandResponse, TextBufferReader, EditorBuffer};
use std::io::Read;
use std::path::PathBuf;
#[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 mut target = EditorBuffer::new();
assert!(matches!(
target.execute(Command::OpenFile(test_file_path)),
CommandResponse::Success(_)
));
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 mut target = EditorBuffer::new();
match target.execute(Command::OpenFile(test_file_path)) {
CommandResponse::Failure(s) => assert_eq!(expected_message, s),
_ => panic!(),
}
}
}

View File

@ -1,8 +1,7 @@
use std::path::PathBuf; use std::path::PathBuf;
use crate::{Point, TextBuffer, TextBufferWriter}; use crate::{Point, TextBuffer};
mod io;
mod command; mod command;
pub use command::{Command, Movement, Unit}; pub use command::{Command, Movement, Unit};
@ -13,11 +12,7 @@ pub struct EditorBuffer {
filepath: Option<PathBuf>, filepath: Option<PathBuf>,
} }
#[derive(Debug)] pub enum CommandResponse {}
pub enum CommandResponse {
Success(String),
Failure(String),
}
impl EditorBuffer { impl EditorBuffer {
/// Create new empty [EditorBuffer] /// Create new empty [EditorBuffer]
@ -40,6 +35,14 @@ impl EditorBuffer {
} }
} }
fn open_file(&mut self, _filepath: PathBuf) -> CommandResponse {
todo!()
}
fn save_file(&mut self, _filepath: Option<PathBuf>) -> CommandResponse {
todo!()
}
fn move_cursor_to_point(&mut self, _point: Point) -> CommandResponse { fn move_cursor_to_point(&mut self, _point: Point) -> CommandResponse {
todo!() todo!()
} }

View File

@ -1,4 +1,4 @@
mod text_buffer; mod text_buffer;
pub use text_buffer::{Point, TextBuffer, TextBufferReader, TextBufferWriter}; pub use text_buffer::{Point, TextBuffer, TextBufferReader, TextBufferWriter};
mod editor_buffer; mod editor_buffer;
pub use editor_buffer::{Command, CommandResponse, EditorBuffer}; pub use editor_buffer::{Command,EditorBuffer};

View File

@ -1,50 +1,25 @@
use super::{Point, TextBuffer}; use super::{Point, TextBuffer};
pub struct TextBufferWriter<'a> { pub struct TextBufferWriter<'a> {
text_buffer: &'a mut TextBuffer, text_buffer: &'a mut TextBuffer,
/// Stores any partial multi-byte characters that are left over from the
/// last call to `write()`.
overflow: Vec<u8>,
} }
impl<'a> TextBufferWriter<'a> { impl<'a> TextBufferWriter<'a> {
pub fn new(text_buffer: &'a mut TextBuffer) -> Self { pub fn new(text_buffer: &'a mut TextBuffer) -> Self {
Self { Self { text_buffer }
text_buffer,
overflow: vec![],
}
} }
} }
impl<'a> std::io::Write for TextBufferWriter<'a> { impl<'a> std::io::Write for TextBufferWriter<'a> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
// If we get a UTF-8 decoding error, try backing off up to three bytes. self.text_buffer.insert_text(
// We might be in the middle of a multipart character and in that case str::from_utf8(buf).map_err(std::io::Error::other)?,
// we should store the partial character in `overflow`. Not the most Point::End,
// efficient way to do this, ideally I should write some way to decode );
// text one character at a time.
let bytes = if !self.overflow.is_empty() {
self.overflow.extend_from_slice(buf);
&self.overflow
} else {
buf
};
let text = str::from_utf8(bytes)
.or_else(|_| str::from_utf8(&bytes[0..bytes.len() - 1]))
.or_else(|_| str::from_utf8(&bytes[0..bytes.len() - 2]))
.or_else(|_| str::from_utf8(&bytes[0..bytes.len() - 3]))
.map_err(std::io::Error::other)?;
self.text_buffer.insert_text(text, Point::End);
self.overflow = bytes[text.len()..bytes.len()].to_vec();
Ok(buf.len()) Ok(buf.len())
} }
fn flush(&mut self) -> std::io::Result<()> { fn flush(&mut self) -> std::io::Result<()> {
if !self.overflow.is_empty() {
self.text_buffer.insert_text(
str::from_utf8(&self.overflow).map_err(std::io::Error::other)?,
Point::End,
);
}
Ok(()) Ok(())
} }
} }

File diff suppressed because it is too large Load Diff