use std::rc::Rc; mod rope; use rope::Rope; pub struct TextBuffer { contents: Rc, } pub enum Point { End, } impl TextBuffer { pub fn new() -> Self { Self { contents: Rope::empty(), } } pub fn num_bytes(&self) -> usize { self.contents.total_bytes() } pub fn num_chars(&self) -> usize { self.contents.total_chars() } pub fn num_lines(&self) -> usize { let num_chars = self.num_chars(); if num_chars == 0 { 0 } else { dbg!(self.contents.total_lines()) + if self .contents .get_char_at_index(self.contents.total_chars() - 1) == '\n' { 0 } else { 1 } } } pub fn insert_char(&mut self, c: char, point: Point) { match point { Point::End => { self.contents = self .contents .insert_at_char_index(self.contents.total_chars(), c) } } } } impl Default for TextBuffer { fn default() -> Self { Self::new() } } #[cfg(test)] mod tests { use super::*; #[test] fn new_creates_empty_buffer() { let target = TextBuffer::new(); assert_eq!(0, target.num_bytes()); assert_eq!(0, target.num_chars()); assert_eq!(0, target.num_lines()); } #[test] fn insert_char_at_end_increases_counts_as_expected() { let mut target = TextBuffer::new(); target.insert_char('A', Point::End); assert_eq!(1, target.num_bytes()); assert_eq!(1, target.num_chars()); assert_eq!(1, target.num_lines()); target.insert_char(' ', Point::End); assert_eq!(2, target.num_bytes()); assert_eq!(2, target.num_chars()); assert_eq!(1, target.num_lines()); target.insert_char('c', Point::End); assert_eq!(3, target.num_bytes()); assert_eq!(3, target.num_chars()); assert_eq!(1, target.num_lines()); target.insert_char('a', Point::End); assert_eq!(4, target.num_bytes()); assert_eq!(4, target.num_chars()); assert_eq!(1, target.num_lines()); target.insert_char('t', Point::End); assert_eq!(5, target.num_bytes()); assert_eq!(5, target.num_chars()); assert_eq!(1, target.num_lines()); target.insert_char('\n', Point::End); assert_eq!(6, target.num_bytes()); assert_eq!(6, target.num_chars()); assert_eq!(1, target.num_lines()); target.insert_char('A', Point::End); assert_eq!(7, target.num_bytes()); assert_eq!(7, target.num_chars()); assert_eq!(2, target.num_lines()); target.insert_char('\n', Point::End); assert_eq!(8, target.num_bytes()); assert_eq!(8, target.num_chars()); assert_eq!(2, target.num_lines()); target.insert_char('\n', Point::End); assert_eq!(9, target.num_bytes()); assert_eq!(9, target.num_chars()); assert_eq!(3, target.num_lines()); target.insert_char('*', Point::End); assert_eq!(10, target.num_bytes()); assert_eq!(10, target.num_chars()); assert_eq!(4, target.num_lines()); target.insert_char('*', Point::End); assert_eq!(11, target.num_bytes()); assert_eq!(11, target.num_chars()); assert_eq!(4, target.num_lines()); target.insert_char(' ', Point::End); assert_eq!(12, target.num_bytes()); assert_eq!(12, target.num_chars()); assert_eq!(4, target.num_lines()); target.insert_char('猫', Point::End); assert_eq!(15, target.num_bytes()); assert_eq!(13, target.num_chars()); assert_eq!(4, target.num_lines()); target.insert_char(' ', Point::End); assert_eq!(16, target.num_bytes()); assert_eq!(14, target.num_chars()); assert_eq!(4, target.num_lines()); target.insert_char('\n', Point::End); assert_eq!(17, target.num_bytes()); assert_eq!(15, target.num_chars()); assert_eq!(4, target.num_lines()); target.insert_char('_', Point::End); assert_eq!(18, target.num_bytes()); assert_eq!(16, target.num_chars()); assert_eq!(5, target.num_lines()); } }