|
| 1 | +use std::cmp; |
| 2 | +// use unicode_segmentation::UnicodeSegmentation; |
| 3 | + |
| 4 | +use tui::layout::Rect; |
| 5 | + |
| 6 | +use super::events::Key; |
| 7 | + |
| 8 | +pub struct Row { |
| 9 | + string: String, |
| 10 | + len: usize, |
| 11 | +} |
| 12 | + |
| 13 | +impl From<&str> for Row { |
| 14 | + fn from(slice: &str) -> Self { |
| 15 | + Self { |
| 16 | + string: String::from(slice), |
| 17 | + len: slice.len() |
| 18 | + } |
| 19 | + } |
| 20 | +} |
| 21 | + |
| 22 | +impl Row { |
| 23 | + pub fn render(&self, start: usize, end: usize) -> String { |
| 24 | + let end = cmp::min(end, self.string.len()); |
| 25 | + let start = cmp::min(start, end); |
| 26 | + self.string.get(start..end).unwrap_or_default().to_string() |
| 27 | + } |
| 28 | + |
| 29 | + // pub fn update_len(&mut self) { |
| 30 | + // self.len = self.string[..].graphemes(true).count(); |
| 31 | + // } |
| 32 | + |
| 33 | + // pub fn insert(&mut self, at: usize, c: char) { |
| 34 | + // if at >= self.len() { |
| 35 | + // self.string.push(c); |
| 36 | + // } else { |
| 37 | + // let mut result: String = self.string[..].graphemes(true).take(at).collect(); |
| 38 | + // let remainder: String = self.string[..].graphemes(true).skip(at).collect(); |
| 39 | + // result.push(c); |
| 40 | + // result.push_str(&remainder); |
| 41 | + // self.string = result; |
| 42 | + // } |
| 43 | + // self.update_len(); |
| 44 | + // } |
| 45 | + |
| 46 | + // pub fn len(&self) -> usize { |
| 47 | + // self.len |
| 48 | + // } |
| 49 | +} |
| 50 | + |
| 51 | +#[derive(Default)] |
| 52 | +pub struct Document { |
| 53 | + rows: Vec<Row>, |
| 54 | +} |
| 55 | + |
| 56 | +impl Document { |
| 57 | + pub fn new(content: String) -> Self { |
| 58 | + let mut rows = Vec::new(); |
| 59 | + for value in content.lines() { |
| 60 | + rows.push(Row::from(value)); |
| 61 | + } |
| 62 | + Self { rows } |
| 63 | + } |
| 64 | + |
| 65 | + pub fn row(&self, index: usize) -> Option<&Row> { |
| 66 | + self.rows.get(index) |
| 67 | + } |
| 68 | + |
| 69 | + pub fn is_empty(&self) -> bool { |
| 70 | + self.rows.is_empty() |
| 71 | + } |
| 72 | + |
| 73 | + pub fn len(&self) -> usize { |
| 74 | + self.rows.len() |
| 75 | + } |
| 76 | + |
| 77 | + // pub fn insert(&mut self, at: &Position, c: char) { |
| 78 | + // if at.y == self.len() { |
| 79 | + // let mut row = Row::default(); |
| 80 | + // row.insert(0, c); |
| 81 | + // self.rows.push(row); |
| 82 | + // } else if at.y < self.len() { |
| 83 | + // let row = self.rows.get_mut(at.y).unwrap(); |
| 84 | + // row.insert(at.x, c); |
| 85 | + // } |
| 86 | + // } |
| 87 | +} |
| 88 | + |
| 89 | +#[derive(Default)] |
| 90 | +pub struct Position { |
| 91 | + pub x: usize, |
| 92 | + pub y: usize, |
| 93 | +} |
| 94 | + |
| 95 | +pub struct Editor { |
| 96 | + cursor_position: Position, |
| 97 | + document: Document, |
| 98 | +} |
| 99 | + |
| 100 | +impl Editor { |
| 101 | + pub fn new() -> Self { |
| 102 | + Self { |
| 103 | + cursor_position: Position::default(), |
| 104 | + document: Document::new(String::new()), |
| 105 | + } |
| 106 | + } |
| 107 | + |
| 108 | + pub fn set_content(&mut self, content: String) { |
| 109 | + self.cursor_position = Position::default(); |
| 110 | + self.document = Document::new(content); |
| 111 | + } |
| 112 | + |
| 113 | + // pub fn clear(&mut self) { |
| 114 | + // self.cursor_position = Position::default(); |
| 115 | + // self.document = Document::new(String::new()) |
| 116 | + // } |
| 117 | + |
| 118 | + pub fn render_row(&self, row: &Row, area: Rect) -> String { |
| 119 | + let start = 0; |
| 120 | + let end = area.width as usize; |
| 121 | + row.render(start, end) |
| 122 | + } |
| 123 | + |
| 124 | + pub fn render_rows(&self, area: Rect) -> Vec<String> { |
| 125 | + let height = area.height; |
| 126 | + let mut rendered_rows = vec![]; |
| 127 | + for terminal_row in 0..height - 1 { |
| 128 | + if let Some(row) = self.document.row(terminal_row as usize) { |
| 129 | + rendered_rows.push(self.render_row(row, area)); |
| 130 | + } |
| 131 | + } |
| 132 | + rendered_rows |
| 133 | + } |
| 134 | + |
| 135 | + fn refresh_screen(&self) -> Result<(), std::io::Error> { |
| 136 | + // Terminal::cursor_hide(); |
| 137 | + // Terminal::cursor_position(&Position::default()); |
| 138 | + |
| 139 | + // if self.should_quit { |
| 140 | + // Terminal::clear_screen(); |
| 141 | + // println!("Goodbye.\r"); |
| 142 | + // } else { |
| 143 | + // self.draw_rows(); |
| 144 | + // Terminal::cursor_position(&self.cursor_position); |
| 145 | + // } |
| 146 | + |
| 147 | + // Terminal::cursor_show(); |
| 148 | + // Terminal::flush() |
| 149 | + Ok(()) |
| 150 | + } |
| 151 | + |
| 152 | + pub fn move_cursor(&mut self, area: Rect, key: Key) { |
| 153 | + let Position { mut x, mut y } = self.cursor_position; |
| 154 | + let height = area.height.saturating_sub(1) as usize; |
| 155 | + let width = area.width.saturating_sub(1) as usize; |
| 156 | + |
| 157 | + match key { |
| 158 | + Key::Up => y = y.saturating_sub(1), |
| 159 | + Key::Down => { |
| 160 | + if y < height { |
| 161 | + y = y.saturating_add(1) |
| 162 | + } |
| 163 | + } |
| 164 | + Key::Left => x = x.saturating_sub(1), |
| 165 | + Key::Right => { |
| 166 | + if x < width { |
| 167 | + x = x.saturating_add(1) |
| 168 | + } |
| 169 | + } |
| 170 | + // Key::PageUp => y = 0, |
| 171 | + // Key::PageDown => y = height, |
| 172 | + // Key::Home => x = 0, |
| 173 | + // Key::End => x = width, |
| 174 | + _ => (), |
| 175 | + } |
| 176 | + self.cursor_position = Position { x, y }; |
| 177 | + } |
| 178 | +} |
0 commit comments