aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/main.rs21
-rw-r--r--src/rope.rs96
2 files changed, 116 insertions, 1 deletions
diff --git a/src/main.rs b/src/main.rs
index e7a11a9..5302d59 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,22 @@
+mod rope;
+
+use rope::Rope;
+use std::ffi::OsString;
+use std::path::Path;
+
fn main() {
- println!("Hello, world!");
+ let args: Vec<OsString> = std::env::args_os().collect();
+ if args.len() != 2 {
+ println!("Usage: edit <filename>");
+ std::process::exit(1);
+ }
+ let file = Path::new(&args[1]);
+ let r = match Rope::open(file) {
+ Ok(r) => r,
+ Err(err) => {
+ println!("FAIL: open file {}: {}", file.to_string_lossy(), err);
+ std::process::exit(1);
+ }
+ };
+ println!("{}", r);
}
diff --git a/src/rope.rs b/src/rope.rs
new file mode 100644
index 0000000..437d5e3
--- /dev/null
+++ b/src/rope.rs
@@ -0,0 +1,96 @@
+use std::fmt::{Display, Error, Formatter};
+use std::fs::File;
+use std::io::{ErrorKind, Read};
+use std::path::Path;
+use std::rc::Rc;
+
+const MAX_NODE_SIZE: usize = 512;
+
+struct Branch {
+ len: usize,
+ left: Rc<Node>,
+ right: Rc<Node>,
+}
+
+enum Node {
+ Leaf(Vec<u8>),
+ Branch(Branch),
+}
+
+impl Display for Node {
+ fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
+ match self {
+ Node::Leaf(s) => {
+ return write!(f, "{}", String::from_utf8_lossy(s));
+ }
+ Node::Branch(b) => {
+ if let Err(err) = write!(f, "{}", b.left) {
+ return Err(err);
+ }
+ return write!(f, "{}", b.right);
+ }
+ }
+ }
+}
+
+impl Node {
+ fn len(&self) -> usize {
+ return match self {
+ Node::Leaf(v) => v.len(),
+ Node::Branch(b) => b.len,
+ };
+ }
+}
+
+pub struct Rope(Rc<Node>);
+
+impl Display for Rope {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
+ let Rope(n) = self;
+ return write!(f, "{}", n);
+ }
+}
+
+impl Rope {
+ fn concat(self, Rope(other): Rope) -> Rope {
+ let Rope(me) = self;
+ if me.len() == 0 {
+ return Rope(other);
+ }
+ if other.len() == 0 {
+ return Rope(me);
+ }
+ return Rope(Rc::new(Node::Branch(Branch {
+ len: me.len() + other.len(),
+ left: me,
+ right: other,
+ })));
+ }
+
+ pub fn open(path: &Path) -> Result<Rope, String> {
+ let mut f = match File::open(path) {
+ Ok(f) => f,
+ Err(err) => {
+ return Err(format!("open: {}", err));
+ }
+ };
+ let mut rope = Rope(Rc::new(Node::Leaf(vec![])));
+ loop {
+ let mut buf = vec![0; MAX_NODE_SIZE];
+ let n = match f.read(&mut buf) {
+ Ok(n) => n,
+ Err(err) => {
+ if err.kind() == ErrorKind::Interrupted {
+ continue;
+ }
+ return Err(format!("read: {}", err));
+ }
+ };
+ if n == 0 {
+ break;
+ }
+ rope = rope.concat(Rope(Rc::new(Node::Leaf(buf))));
+ }
+ return Ok(rope);
+ }
+}