From 4fdf430f66dd97b52529f9e23a67c67c272f2406 Mon Sep 17 00:00:00 2001 From: Rose Hogenson Date: Wed, 27 Dec 2023 09:37:47 -0800 Subject: Print the first n lines of the file. --- src/main.rs | 6 +++-- src/rope.rs | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 85 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 10d7647..711f920 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,14 +12,16 @@ fn edit(file: &OsStr) -> Result<(), String> { return Err(format!("open file {}: {}", file.to_string_lossy(), err)); } }; - println!("{}", r); let size = match tiocgwinsz::size() { Some(size) => size, None => { return Err(String::from("cannot get terminal size")); } }; - println!("{}, {}", size.ws_row, size.ws_col); + let mut stdout = std::io::stdout(); + if let Err(err) = r.print_lines(&mut stdout, 0, usize::from(size.ws_row)) { + return Err(format!("write: {}", err)); + } return Ok(()); } diff --git a/src/rope.rs b/src/rope.rs index 320cd14..b1b5831 100644 --- a/src/rope.rs +++ b/src/rope.rs @@ -1,6 +1,6 @@ -use std::fmt::{Display, Error, Formatter}; +use std::fmt::{Display, Formatter}; use std::fs::File; -use std::io::{ErrorKind, Read}; +use std::io::{ErrorKind, Read, Write}; use std::path::Path; use std::rc::Rc; @@ -10,6 +10,8 @@ const MAX_NODE_SIZE: usize = 4; struct Branch { left: Rc, right: Rc, + // Number of newline characters under this branch. + lines: usize, } enum Node { @@ -36,10 +38,73 @@ impl Node { _ => false, }; } + + fn lines(&self) -> usize { + match self { + Node::Leaf(v) => { + let mut count = 0; + for &c in v { + if c == b'\n' { + count += 1; + } + } + return count; + } + Node::Branch(b) => { + return b.lines; + } + } + } + + fn print_lines( + &self, + out: &mut dyn Write, + start: usize, + end: usize, + ) -> Result<(), std::io::Error> { + match self { + Node::Leaf(v) => { + let mut nl_count = 0; + let mut start_pos = 0; + let mut end_pos = v.len(); + for (i, &c) in v.iter().enumerate() { + if c != b'\n' { + continue; + } + nl_count += 1; + if nl_count == start { + start_pos = i; + } + if nl_count == end { + end_pos = i + 1; + } + } + if let Err(err) = out.write(&v[start_pos..end_pos]) { + return Err(err); + } + return Ok(()); + } + Node::Branch(b) => { + let right_start; + if start <= b.left.lines() { + if let Err(err) = b.left.print_lines(out, start, end) { + return Err(err); + } + right_start = 0; + } else { + right_start = start - b.left.lines(); + } + if end <= b.left.lines() { + return Ok(()); + } + return b.right.print_lines(out, right_start, end - b.left.lines()); + } + } + } } impl Display for Node { - fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> { let mut buf = Vec::new(); self.write(&mut buf); return write!(f, "{}", String::from_utf8_lossy(&buf)); @@ -57,9 +122,11 @@ impl Rope { if other.empty() { return Rope(me); } + let lines = me.lines() + other.lines(); return Rope(Rc::new(Node::Branch(Branch { left: me, right: other, + lines: lines, }))); } @@ -89,10 +156,20 @@ impl Rope { } return Ok(rope); } + + pub fn print_lines( + &self, + out: &mut dyn Write, + start: usize, + end: usize, + ) -> Result<(), std::io::Error> { + let Rope(me) = self; + return me.print_lines(out, start, end); + } } impl Display for Rope { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { let Rope(n) = self; return write!(f, "{}", n); } -- cgit v1.3.1